DoctrineのEntity Manager
Entityを管理するobject
DBとEntityの仲介をする
コード内では$emという名前で変数に入れられる事が多い
DBに保存する流れ
Entityをinstantiateして、それに対してゴニョって値の更新などを行う
保存したいinstanceにpersist()を適用する
新しくなったEntityがDoctrineの管理下に入る
元のEntityとの差分などを管理している
flush()を実行する
差分を実際にDBに適用する
SQLを発行してごにょごにょというのを勝手にやっている
このタイミングで初めてDBが更新される
code:ノリ.php
$inquiry = new InruiryEntity();
$inquiry->setName('hoge'); // Entityを更新
..
$em = $this->getDoctrine()->getManager(); // entity managerを取得
$em->persist($inquiry); // emに入れる
$em->flush(); // DBを更新
既存のdataの1つpropertyだけ更新したいときも新しくinstantiateしないといけないの?
新しくinstantiateするか、
既存のやつをどこかから(e.g. FormBuilderで作ったform)持ってきて、setHogeして、persistする感じか
DBから読み込むときの流れ
DBに入っていることを意識せず、Entity Managerに入っているものとして扱う
repositoryを取得
repositoryに対してfindなどをする
code:ノリ.php
$em = $this->getDoctrine()->getManager(); // entity managerを取得
$hogeRepository = $em->getRepository('Hoge');
$list = $hogeRepository->find(...);
flush()の引数
flushとpersistが分かれていることの利点
GPT-4.icon
persistとflushが分かれている理由は、柔軟なデータ操作と効率的なトランザクション管理を可能にするためです。一度にsave($entity)のように単一メソッドで永続化と反映を行う設計も可能ですが、それではDoctrineが提供する利点を活かしきれません。それぞれ分かれていることで得られる具体的なメリットは以下の通りです。
1. 一度に複数のエンティティを追加・更新する効率性
persistとflushを分けることで、複数のエンティティを一括でデータベースに保存できます。例えば、関連するエンティティを複数persistし、最後にflushすることで、まとめて1回のトランザクションでデータベースに反映できます。
saveのように逐次的に永続化と反映を行うと、複数のSQLクエリが個別に発行されてしまい、パフォーマンスが低下します。persistとflushを分けることで、データベースへの負荷を抑えつつ、高速なデータ保存が可能です。
2. トランザクション管理がしやすい
persistを複数のエンティティに適用し、flushでまとめて実行することで、1つのトランザクションとして扱えます。これにより、すべての変更が確実にデータベースに反映されるか、あるいは失敗した場合にはロールバックされるため、データの一貫性を確保しやすくなります。
逐次的なsaveではトランザクションの概念が薄くなり、データ整合性の管理が難しくなります。
3. エンティティの操作順序や依存関係の調整
永続化の対象としてpersistでエンティティを指定した後に、依存する他のエンティティに対しても処理を加えられます。これにより、関連するエンティティ間で依存関係がある場合でも、適切な順序で操作ができます。
saveだけだと、このような順序調整が難しくなり、途中で依存関係の処理を挟む場合に問題が発生する可能性が高くなります。
4. オブジェクトの状態管理を詳細に制御できる
Doctrineはエンティティのライフサイクル(new, managed, removedなど)を細かく管理するため、persistとflushを分けることで、データベース反映前のエンティティの状態を保持・追跡できます。
例えば、一連の処理の中で、あるエンティティだけが永続化の対象であるか(persist済みかどうか)を確認したり、途中で状態を変更するようなケースにおいても柔軟に対応できます。
5. バッチ処理やパフォーマンス向上
多数のエンティティを処理する場合、一定の数ごとにflushを呼び出して反映することで、メモリの使用量を管理しつつデータベースの負荷を抑えられます。このようなバッチ処理が可能なのは、persistとflushが分かれているからです。
saveに全てのエンティティを渡すような操作だと、バッチ処理やパフォーマンス管理が難しくなります。
具体的な例
例えば、ある商品とその複数の画像をデータベースに保存する処理を考えます。この場合、persistで商品と画像を一つずつ永続化対象にし、最後にflushすることでまとめて保存します。これにより、関連するデータが一度にトランザクションとして反映され、個別にクエリが発行されるのを避けられます。
code:php
$product = new Product();
$product->setName('Example Product');
$entityManager->persist($product);
foreach ($images as $image) {
$productImage = new ProductImage();
$productImage->setFileName($image->getFileName());
$productImage->setProduct($product);
$entityManager->persist($productImage);
}
// ここでまとめて保存
$entityManager->flush();